using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Universe.OneC
{
    public class Adapter1C : IDisposable
    {
        public readonly AdapterUsageMode _Mode;
        private object connector;
        private bool disposed;
        private object framework;
        private object server;

        public Adapter1C() : this(AdapterUsageMode.Connector)
        {
        }

        public Adapter1C(AdapterUsageMode mode)
        {
            this._Mode = mode;
        }

        public void ConnectServer(ServerInfo info)
        {
            Type typeFromProgID = Type.GetTypeFromProgID("V8" + ((info.Version == 0) ? "" : info.Version.ToString()) + ".ComConnector", true);
            this.connector = Activator.CreateInstance(typeFromProgID);
            if (info.Version == 0)
            {
                this.server = this.connector.Call("ConnectServer", new object[] { info.Address });
                object[] objArray = (object[]) this.server.Call("GetInfoBases", null);
                if ((objArray != null) && (objArray.Length > 0))
                {
                    info.InfoBases.Clear();
                    info.Clusters.Clear();
                    for (int i = 0; i < objArray.GetLength(0); i++)
                    {
                        object target = objArray.GetValue(i);
                        InfoBase item = new InfoBase(info, (string) target.Get("Name"));
                        info.InfoBases.Add(item);
                        this.ReleaseObject(ref target);
                    }
                }
            }
            else
            {
                if ((info.Version != 1) && (info.Version != 2))
                {
                    throw new ArgumentException("Version number " + info.Version.ToString() + " is not supported.");
                }
                this.server = this.connector.Call("ConnectAgent", new object[] { info.Address });
                this.server.Call("AuthenticateAgent", new object[] { info.UserName, info.Password });
                object[] objArray2 = (object[]) this.server.Call("GetClusters", null);
                if ((objArray2 != null) && (objArray2.Length > 0))
                {
                    info.InfoBases.Clear();
                    info.Clusters.Clear();
                    for (int j = 0; j < objArray2.GetLength(0); j++)
                    {
                        object obj3 = objArray2.GetValue(j);
                        Cluster cluster = new Cluster(info);
                        cluster.Name = (string) obj3.Get("Name");
                        cluster.HostName = (string) obj3.Get("HostName");
                        cluster.MainPort = (int) obj3.Get("MainPort");
                        info.Clusters.Add(cluster);
                        this.ReleaseObject(ref obj3);
                    }
                }
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                this.ReleaseObject(ref this.server);
                this.ReleaseObject(ref this.framework);
                this.ReleaseObject(ref this.connector);
                if (disposing)
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            this.disposed = true;
        }

        ~Adapter1C()
        {
            this.Dispose(false);
        }

        public void GetClusterInfo(Cluster cluster)
        {
            if (cluster.Server.Version == 0)
            {
                throw new ArgumentException("Version number 8.0 is not supported.");
            }
            object target = this.server.Call("CreateClusterInfo", null);
            target.Set("Name", cluster.Name);
            target.Set("HostName", cluster.HostName);
            target.Set("MainPort", cluster.MainPort);
            this.server.Call("Authenticate", new object[] { target, cluster.UserName, cluster.Password });
            cluster.WorkingProcesses.Clear();
            cluster.InfoBases.Clear();
            object[] objArray = (object[]) this.server.Call("GetWorkingProcesses", new object[] { target });
            if ((objArray != null) && (objArray.Length > 0))
            {
                for (int i = 0; i < objArray.GetLength(0); i++)
                {
                    object obj3 = objArray.GetValue(i);
                    WorkingProcess item = new WorkingProcess(cluster);
                    item.HostName = (string) obj3.Get("HostName");
                    item.MainPort = (int) obj3.Get("MainPort");
                    cluster.WorkingProcesses.Add(item);
                    this.ReleaseObject(ref obj3);
                }
            }
            object[] objArray2 = (object[]) this.server.Call("GetInfoBases", new object[] { target });
            if ((objArray2 != null) && (objArray2.Length > 0))
            {
                for (int j = 0; j < objArray2.GetLength(0); j++)
                {
                    object obj4 = objArray2.GetValue(j);
                    InfoBase base2 = new InfoBase(cluster, (string) obj4.Get("Name"));
                    cluster.InfoBases.Add(base2);
                    this.ReleaseObject(ref obj4);
                }
            }
            this.ReleaseObject(ref target);
        }

        public void GetInfoBaseInfo(InfoBase infobase)
        {
            if (infobase.Server.Version == 0)
            {
                this.server.Call("AddAuthentication", new object[] { infobase.UserName, infobase.Password });
                object[] objArray = (object[]) this.server.Call("GetInfoBases", null);
                if ((objArray != null) && (objArray.Length > 0))
                {
                    for (int i = 0; i < objArray.GetLength(0); i++)
                    {
                        object target = objArray.GetValue(i);
                        if (infobase.Name == ((string) target.Get("Name")))
                        {
                            infobase.dbServerName = (string) target.Get("DBServerName");
                            infobase.dbName = (string) target.Get("DBName");
                            infobase.dbUser = (string) target.Get("DBUser");
                            infobase.dbPassword = "";
                        }
                        this.ReleaseObject(ref target);
                    }
                }
            }
            else
            {
                bool flag = false;
                foreach (WorkingProcess process in infobase.Cluster.WorkingProcesses)
                {
                    object obj3 = this.connector.Call("ConnectWorkingProcess", new object[] { process.Address });
                    obj3.Call("AddAuthentication", new object[] { infobase.UserName, infobase.Password });
                    object[] objArray2 = (object[]) obj3.Call("GetInfoBases", null);
                    if ((objArray2 != null) && (objArray2.Length > 0))
                    {
                        for (int j = 0; j < objArray2.GetLength(0); j++)
                        {
                            object obj4 = objArray2.GetValue(j);
                            if (infobase.Name == ((string) obj4.Get("Name")))
                            {
                                infobase.DBMS = (string) obj4.Get("DBMS");
                                infobase.dbServerName = (string) obj4.Get("dbServerName");
                                infobase.dbName = (string) obj4.Get("dbName");
                                infobase.dbUser = (string) obj4.Get("dbUser");
                                infobase.dbPassword = "";
                                flag = true;
                            }
                            this.ReleaseObject(ref obj4);
                        }
                    }
                    this.ReleaseObject(ref obj3);
                    if (flag)
                    {
                        break;
                    }
                }
            }
        }

        public object GetMetadata()
        {
            return this.framework.Get("Metadata");
        }

        public object NewObject(string name)
        {
            return this.framework.Call("NewObject", new object[] { name });
        }

        public object GetProcessor(string processorName)
        {
            object all = null, proc = null, instance = null;
            try
            {
                all = this.GlobalProperty("Обработки");
                proc = all.Get(processorName);
                instance = proc.Call("Создать");
                return instance;
            }
            finally
            {
                proc.ReleaseComObject();
                all.ReleaseComObject();
            }
        }

        public object GlobalMethod(string name, params object[] args)
        {
            return this.framework.Call(name, args);
        }

        public object GlobalProperty(string name)
        {
            return this.framework.Get(name);
        }

        public void Open(string connectionString, string progId)
        {
            Open2(connectionString, progId);
        }

        public void Open(InfoBase infobase)
        {
            string connectionString = infobase.Address;
            string progId = null;

            string str = "";
            if (infobase.Server == null)
            {
                throw new ArgumentException("Server value can not be null.");
            }
            if (infobase.Server.Version == 0)
            {
                str = "0";
            }
            else if (infobase.Server.Version == 1)
            {
                str = "1";
            }
            else
            {
                if (infobase.Server.Version != 2)
                {
                    throw new ArgumentException("Version number " + infobase.Server.Version.ToString() + " is not supported.");
                }
                str = "2";
            }

            if (this._Mode == AdapterUsageMode.Connector)
            {
                progId = "V8" + str + ".ComConnector";
            }
            else 
            {
                progId = "V8" + str + ".Application";
            }
            


            Open2(connectionString, progId);
        }

        private void Open2(string connectionString, string progId)
        {
            if (this.framework == null)
            {
                Type typeFromProgID = Type.GetTypeFromProgID(progId, true);
                this.connector = Activator.CreateInstance(typeFromProgID);
                Debug.WriteLine("CS: " + connectionString);
                this.framework = this.connector.Call("Connect", new object[] { connectionString });
                if (((this.framework != null) && (this.framework.GetType() == typeof(bool))) && ((bool) this.framework))
                {
                    this.framework = this.connector;
                }
            }
        }

        public void ReleaseObject(ref object target)
        {
            if ((target != null) && target.GetType().IsCOMObject)
            {
                Marshal.ReleaseComObject(target);
            }
            target = null;
        }

        public string String(object value)
        {
            return (string) this.framework.Call("String", new object[] { value });
        }

        public string XMLType(object type)
        {
            object target = this.framework.Call("XMLТип", new object[] { type });
            string str = (string) target.Get("ИмяТипа");
            this.ReleaseObject(ref target);
            return str;
        }

        public AdapterUsageMode Mode
        {
            get
            {
                return this._Mode;
            }
        }
    }
}